package com.kordar.admin.config;

import com.baomidou.dynamic.datasource.processor.DsProcessor;
import com.baomidou.dynamic.datasource.processor.DsSessionProcessor;
import com.baomidou.dynamic.datasource.processor.DsSpelExpressionProcessor;
import com.baomidou.dynamic.datasource.provider.AbstractJdbcDataSourceProvider;
import com.baomidou.dynamic.datasource.provider.DynamicDataSourceProvider;
import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@MapperScan(basePackages = {"com.kordar.auth", "com.kordar.rbac", "com.kordar.admin.modular.sys.mapper"})
@EnableTransactionManagement
@Configuration
public class KordarBatisPlusConfig {


    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
        HashMap<String, TableNameHandler> map = new HashMap<>();

        String[] tables = {"sys_admin", "sys_auth_assignment", "sys_auth_item", "sys_auth_item_child", "sys_auth_rule", "sys_dict", "sys_dict_type", "sys_setting"};
        MyTableNameHandler tableNameHandler = new MyTableNameHandler();
        for (String tbl : tables) {
            map.put(tbl, tableNameHandler);
        }
        dynamicTableNameInnerInterceptor.setTableNameHandlerMap(map);
        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
        // 注册乐观锁
        interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
        return interceptor;
    }


    private static class MyTableNameHandler implements TableNameHandler {
        @Override
        public String dynamicTableName(String sql, String tableName) {
            Subject subject = SecurityUtils.getSubject();
            String tenant = (String) Optional.ofNullable(subject.getSession().getAttribute("tenant")).orElse("");
            return tenant.isEmpty() ? tableName : tenant + "_" + tableName;
        }
    }

    @Bean
    @ConditionalOnMissingBean
    public DsProcessor dsProcessor() {
        DsShiroProcessor dsShiroProcessor = new DsShiroProcessor();
        DsSessionProcessor sessionProcessor = new DsSessionProcessor();
        DsSpelExpressionProcessor spelExpressionProcessor = new DsSpelExpressionProcessor();
        dsShiroProcessor.setNextProcessor(sessionProcessor);
        sessionProcessor.setNextProcessor(spelExpressionProcessor);
        return dsShiroProcessor;
    }

    @Value("${kordar.datasource.driver}")
    private String driver;
    @Value("${kordar.datasource.url}")
    private String url;
    @Value("${kordar.datasource.username}")
    private String username;
    @Value("${kordar.datasource.password}")
    private String password;

    @Bean
    public DynamicDataSourceProvider dynamicDataSourceProvider() {
        return new AbstractJdbcDataSourceProvider(driver, url, username, password) {
            @Override
            protected Map<String, DataSourceProperty> executeStmt(Statement statement) throws SQLException {
                ResultSet rs = statement.executeQuery("select * from sys_datasource where active = 1");
                Map<String, DataSourceProperty> map = new HashMap<>();
                DataSourceProperty property1 = new DataSourceProperty();
                property1.setUrl(url);
                property1.setUsername(username);
                property1.setPassword(password);
                property1.setDriverClassName(driver);
                map.put("master", property1);
                while (rs.next()) {
                    String name = rs.getString("name");
                    String username = rs.getString("username");
                    String password = rs.getString("password");
                    String url = rs.getString("url");
                    String driver = rs.getString("driver");
                    DataSourceProperty property = new DataSourceProperty();
                    property.setUsername(username);
                    property.setPassword(password);
                    property.setUrl(url);
                    property.setDriverClassName(driver);
                    map.put(name, property);
                }
                return map;
            }
        };
    }

}
